﻿Imports System.Reflection

Class Window1
	Implements IFilter
	Public list As New List(Of ClassData)
	Public Shared classes As New Dictionary(Of String, ClassData)
	Public Shared _levels As Integer = 0
	Public Shared _window As Window1
	Private _previous As New Stack(Of String)
	Private _next As New Stack(Of String)

	Private _navigating = False
	Private WithEvents _timer As New Timers.Timer(100)

	Sub New()
		InitializeComponent()
		If My.Settings.width > 0 AndAlso My.Settings.height > 0 Then
			Me.Width = My.Settings.width
			Me.Height = My.Settings.height
		End If
		_window = Me
		Call SetScale(My.Settings.scale)
		ctlAccess.IsEditable = True
		ctlInheritsFrom.IsEditable = True
		ctlNamespaces.IsEditable = True
		ctlFilter.ControlResources = My.Settings.itemResources
		ctlFilter.ItemTemplate = My.Settings.itemTemplate
	End Sub
	Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
		ctlFilter.Filter = Me
		Call SetLabelColor()
		ctlFilter.Focus()
		Call BuildList()
	End Sub
	Private Sub BuildList()
		ctlWait.Visibility = Windows.Visibility.Visible
		'ctlInfo.Visibility = Windows.Visibility.Collapsed
		'AddHandler Me.BuildDone, AddressOf OnBuildDone
		Dim buildThread = New System.Threading.Thread(AddressOf Building)
		buildThread.Start(False)
	End Sub
	Private Sub Building(ByVal inhertied As Boolean)
		list.Clear()
		Dim filename = "C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\PresentationCore.dll"
		If Not My.Computer.FileSystem.FileExists(filename) Then
			filename = "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\PresentationCore.dll"
		End If
		If Not My.Computer.FileSystem.FileExists(filename) Then
			MsgBox("Can't find .Net assemblies")
		End If
		Dim asm = System.Reflection.Assembly.LoadFile(filename)
		list.AddRange(GetList(asm, inhertied).ToArray)
		filename = "C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\PresentationFramework.dll"
		If Not My.Computer.FileSystem.FileExists(filename) Then
			filename = "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\PresentationFramework.dll"
		End If
		If Not My.Computer.FileSystem.FileExists(filename) Then
			MsgBox("Can't find .Net assemblies")
		End If
		asm = System.Reflection.Assembly.LoadFile(filename)
		list.AddRange(GetList(asm, inhertied).ToArray)
		For Each item In list
			If Not classes.ContainsKey(item.Name) Then
				classes.Add(item.Name, item)
			End If
		Next
		Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, New Action(AddressOf OnBuildDone))
	End Sub
	Private Sub OnBuildDone()
		If Not Dispatcher.CheckAccess() Then
			Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, New Action(AddressOf OnBuildDone))
		Else
			'RemoveHandler Me.BuildDone, AddressOf OnBuildDone
			ctlWait.Visibility = Windows.Visibility.Collapsed
			'ctlInfo.Visibility = Windows.Visibility.Visible
			If ctlAccess.ItemsSource Is Nothing Then
				ctlAccess.ItemsSource = (From x In list Select x.AccessName Distinct Order By AccessName).ToArray
				ctlInheritsFrom.ItemsSource = (From x In list Select x.Name Distinct Order By Name).ToArray
				ctlImplements.ItemsSource = (From x In list.SelectMany(Function(c) c.ImplementsList) Distinct Order By x Select x).ToArray
				ctlNamespaces.ItemsSource = (From x In list Select x.NamespaceName Distinct Order By NamespaceName).ToArray
			End If
			ctlFilter.UpdateList(True)
			ctlFilter.Focus()
		End If
	End Sub
	Private Function GetList(ByVal asm As Assembly, ByVal all As Boolean) As List(Of ClassData)
		Dim types() = asm.GetExportedTypes()
		Dim list As New List(Of ClassData)
		For Each item In types
			If item.IsVisible Or Not item.IsNested Or (item.IsNested And item.IsNestedPublic) Then
				list.Add(New ClassData(item, all))
			End If
		Next
		Return (From x In list Order By x.Name Select x).ToList
	End Function
	Public Function GetList1(ByVal matchText As String) As Object Implements IFilter.GetList
		Dim query = From x In list Where UCase(x.Name) Like "*" + UCase(matchText) + "*" Select x
		If ctlAccess.Text <> String.Empty Then
			query = query.Where(Function(c) UCase(c.AccessName) = UCase(ctlAccess.Text))
		End If
		If ctlInheritsFrom.Text <> String.Empty Then
			query = query.Where(Function(c) (From x In c.InheritsFrom Where UCase(x) = UCase(ctlInheritsFrom.Text)).Count > 0)
		End If
		If ctlImplements.Text <> String.Empty Then
			query = query.Where(Function(c) (From x In c.ImplementsList Where UCase(x) = UCase(ctlImplements.Text)).Count > 0)
		End If
		If ctlNamespaces.Text <> String.Empty Then
			query = query.Where(Function(c) UCase(c.NamespaceName) = UCase(ctlNamespaces.Text))
		End If
		Dim resp = query.ToArray
		Return resp
	End Function
	Private Sub ClearCriteria()
		ctlAccess.Text = String.Empty
		ctlInheritsFrom.Text = String.Empty
		ctlImplements.Text = String.Empty
		ctlNamespaces.Text = String.Empty
		ctlFilter.Text = String.Empty
	End Sub
	Private Sub ctlAccess_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ctlInheritsFrom.LostFocus, ctlNamespaces.LostFocus, ctlImplements.LostFocus
		ctlFilter.UpdateList()
	End Sub
	Private Sub SetScale(ByVal scale As Double)
		scale = Math.Max(Math.Min(4.0, scale), 0.3)
		Dim x As New ScaleTransform(scale, scale, 0, 0)
		Me.Content.LayoutTransform = x
		My.Settings.scale = scale
		My.Settings.Save()
	End Sub
	Private Sub Window1_PreviewMouseWheel(ByVal sender As Object, ByVal e As System.Windows.Input.MouseWheelEventArgs) Handles Me.PreviewMouseWheel
		If Keyboard.Modifiers <> ModifierKeys.Control Then Exit Sub
		Dim scale = If(e.Delta < 0, 0.1#, -0.1#)
		Call SetScale(My.Settings.scale + scale)
		e.Handled = True
	End Sub
	Private Sub Window1_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles Me.SizeChanged
		My.Settings.width = Me.Width
		My.Settings.height = Me.Height
		My.Settings.Save()
	End Sub
	Private Sub ctlImplementsList_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles ctlImplementsList.MouseDoubleClick
		If _navigating Then Exit Sub
		_navigating = True
		_timer.Start()
		If ctlFilter.SelectedItem IsNot Nothing Then _previous.Push(ctlFilter.SelectedItem.Name)
		Dim value = ctlImplementsList.SelectedItem
		Call ClearCriteria()
		ctlImplements.Text = value
		ctlImplementsList.SelectionMode = SelectionMode.Multiple
		ctlImplementsList.SelectedItems.Clear()
		ctlImplementsList.SelectionMode = SelectionMode.Single
		ctlImplementsList.SelectedItem = Nothing
		ctlImplementsList.SelectedIndex = -1
		ctlFilter.UpdateList()
		ctlFilter.Focus()
		Call SetLabelColor()
	End Sub
	Private Sub ctlInheritsFrom_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles ctlInheritsFrom.MouseDoubleClick
		If _navigating Then Exit Sub
		_navigating = True
		_timer.Start()
		If ctlFilter.SelectedItem IsNot Nothing Then _previous.Push(ctlFilter.SelectedItem.Name)
		Dim value = ctlInheritsList.SelectedItem
		Call ClearCriteria()
		ctlInheritsList.SelectedIndex = -1
		ctlFilter.Text = value
		Dim list = TryCast(ctlFilter.List, Array)
		If list IsNot Nothing Then
			For t = 0 To list.Length - 1
				If list(t).Name = ctlFilter.Text Then
					ctlFilter.SetIndex(t)
				End If
			Next
		End If
		ctlFilter.Focus()
		Call SetLabelColor()
	End Sub
	Private Sub ctlInherited_TextChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.TextChangedEventArgs) Handles ctlInherited.TextChanged
		If IsNumeric(ctlInherited.Text) Then
			_levels = CInt(ctlInherited.Text)
		Else
			_levels = 0
		End If
		If ctlFilter IsNot Nothing Then
			Dim item = TryCast(ctlFilter.SelectedItem, ClassData)
			If item IsNot Nothing Then
				Call item.SendNotice()
			End If
		End If
	End Sub
	Private Sub Always_CanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
		e.CanExecute = True
	End Sub
	Private Sub Prior_CanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
		e.CanExecute = _previous.Count > 0
	End Sub
	Private Sub Next_CanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
		e.CanExecute = _next.Count > 0
	End Sub
	Sub SetLabelColor()
		If _previous.Count > 0 Then
			Label1.Foreground = System.Windows.Media.Brushes.Blue
		Else
			Label1.Foreground = System.Windows.Media.Brushes.Gray
		End If
		If _next.Count > 0 Then
			ctlForward.Foreground = System.Windows.Media.Brushes.Blue
		Else
			ctlForward.Foreground = System.Windows.Media.Brushes.Gray
		End If
	End Sub
	Public Sub FocusFilter(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
		e.Handled = True
		ctlFilter.Focus()
	End Sub
	Public Sub GoUp(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
		e.Handled = True
		ctlInheritsList.SelectedIndex = 0
		Call ctlInheritsFrom_MouseDoubleClick(Me, Nothing)
	End Sub
	Private Sub GoBack(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
		e.Handled = True
		If _previous.Count > 0 Then
			_navigating = True
			_timer.Start()
			If ctlFilter.SelectedItem IsNot Nothing Then _next.Push(ctlFilter.SelectedItem.Name)
			Dim value = _previous.Pop
			ctlFilter.Text = value
			Dim list = TryCast(ctlFilter.List, Array)
			If list IsNot Nothing Then
				For t = 0 To list.Length - 1
					If list(t).Name = value Then
						ctlFilter.SetIndex(t)
						Exit For
					End If
				Next
			End If
			ctlFilter.Focus()
		End If
		Call SetLabelColor()
	End Sub
	Private Sub GoNext(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
		e.Handled = True
		If _next.Count > 0 Then
			_navigating = True
			_timer.Start()
			_previous.Push(ctlFilter.SelectedItem.Name)
			Dim value = _next.Pop
			ctlFilter.Text = value
			Dim list = TryCast(ctlFilter.List, Array)
			If list IsNot Nothing Then
				For t = 0 To list.Length - 1
					If list(t).Name = value Then
						ctlFilter.SetIndex(t)
						Exit For
					End If
				Next
			End If
			ctlFilter.Focus()
		End If
		Call SetLabelColor()
	End Sub
	Private Sub ctlFilter_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles ctlFilter.PropertyChanged
		If _navigating Then Return
		If _previous.Count > 0 Then _previous.Clear()
		If _next.Count > 0 Then _next.Clear()
		Call SetLabelColor()
	End Sub
	Private Sub _timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timer.Elapsed
		_timer.Stop()
		_navigating = False
	End Sub
	Private Sub ctlDisplayEvents_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ctlDisplayEvents.Click, ctlDisplayFields.Click, ctlDisplayMethods.Click, ctlDisplayProperties.Click
		ctlFilter.NotifyChange()
	End Sub
	Private Sub Label1_PreviewMouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Label1.PreviewMouseDown
		If _previous.Count > 0 Then
			Call GoBack(Me, Nothing)
		End If
		Call SetLabelColor()
	End Sub
	Private Sub ctlForward_PreviewMouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles ctlForward.PreviewMouseDown
		If _next.Count > 0 Then
			Call GoNext(Me, Nothing)
		End If
		Call SetLabelColor()
	End Sub
End Class